{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 智能指针          | 所有权模型                       | 主要用途                                 | 典型场景                               |\n",
    "| ----------------- | -------------------------------- | ---------------------------------------- | -------------------------------------- |\n",
    "| `std::unique_ptr` | 独占所有权，禁止拷贝、允许移动   | 表示“唯一所有者”，资源不可共享           | 容器元素、工厂函数返回值、自定义删除器 |\n",
    "| `std::shared_ptr` | 共享所有权，通过引用计数共享资源 | 多方共享同一资源，生命周期自动延长       | 图结构、插件系统、缓存                 |\n",
    "| `std::weak_ptr`   | 弱引用，不影响引用计数           | 观察 `shared_ptr` 管理对象，避免循环引用 | 观察者模式、缓存、父子节点互相引用     |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# std::unique_ptr "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`std::unique_ptr` 是 C++11 引入、C++17 中广泛使用的独占所有权智能指针。它通过 RAII 保证所管理对象在离开作用域时自动释放，避免手动调用 `delete` 带来的内存泄漏与异常安全问题。核心特点如下：\n",
    "\n",
    "- **独占所有权**：同一时刻只能有一个 `std::unique_ptr` 指向给定对象，拷贝被禁止，移动被允许。\n",
    "- **零开销抽象**：内部仅保存一个裸指针，不带引用计数，内存占用与裸指针相当。\n",
    "- **异常安全**：配合 `std::make_unique` 创建对象，在构造阶段若抛出异常，可确保已分配内存自动释放。\n",
    "- **自定义删除器**：可指定删除策略（如关闭文件、归还对象池等），扩展 RAII 能力。\n",
    "- **数组支持**：`std::unique_ptr<T[]>` 能正确调用数组元素的析构函数。\n",
    "\n",
    "下面给出三个详细注释的可运行示例，分别展示基础用法、数组管理与自定义删除器。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "示例一：基础独占所有权与移动语义\n",
    "- 通过 `std::move` 转移所有权是唯一合法的“复制”方式。\n",
    "- 资源在 `main` 结束时自动释放，无需 `delete`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[初始] book 指向的内容：深入理解 C++17\n",
      "[移动后] book 已为空，所有权已移交。\n",
      "[移动后] moved_book 指向的内容：深入理解 C++17\n"
     ]
    }
   ],
   "source": [
    "// 示例一：基础独占所有权与移动语义\n",
    "\n",
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <string>\n",
    "\n",
    "{\n",
    "    // 使用 std::make_unique 创建智能指针，异常安全且语法简洁\n",
    "    auto book = std::make_unique<std::string>(\"深入理解 C++17\");\n",
    "    std::cout << \"[初始] book 指向的内容：\" << *book << \"\\n\";\n",
    "\n",
    "    // std::unique_ptr 禁止拷贝，会导致编译错误\n",
    "    // auto copy = book; // ❌ 编译错误：unique_ptr 的拷贝构造被删除\n",
    "\n",
    "    // 可以通过 std::move 将所有权转移给新的 unique_ptr\n",
    "    std::unique_ptr<std::string> moved_book = std::move(book);\n",
    "    if (!book) { // 源对象被移动后变为空指针\n",
    "        std::cout << \"[移动后] book 已为空，所有权已移交。\\n\";\n",
    "    }\n",
    "    std::cout << \"[移动后] moved_book 指向的内容：\" << *moved_book << \"\\n\";\n",
    "\n",
    "    // 离开作用域时，无需手动 delete，资源会自动释放\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 示例一：基础独占所有权与移动语义\n",
    "\n",
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <string>\n",
    "\n",
    "{\n",
    "    // 使用 std::make_unique 创建智能指针，异常安全且语法简洁\n",
    "    auto book = std::make_unique<std::string>(\"深入理解 C++17\");\n",
    "    std::cout << \"[初始] book 指向的内容：\" << *book << \"\\n\";\n",
    "\n",
    "    std::unique_ptr // 禁止拷贝，会导致编译错误; error: no viable constructor or deduction guide for deduction of template arguments of 'unique_ptr'\n",
    "    auto copy = book; // ❌ 编译错误：unique_ptr 的拷贝构造被删除; \n",
    "\n",
    "    return 0;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "示例二：管理动态数组\n",
    "- 数组版本的 `unique_ptr` 需要写成 `std::unique_ptr<T[]>`。\n",
    "- 访问数组元素仍使用 `operator[]`，析构时自动调用 `delete[]`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "numbers 数组内容：0 10 20 30 40\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <memory>\n",
    "\n",
    "{\n",
    "    // 创建一个管理 int 数组的 unique_ptr\n",
    "    std::size_t size = 5;\n",
    "    auto numbers = std::make_unique<int[]>(size);\n",
    "\n",
    "    // 像普通数组一样使用下标访问元素\n",
    "    for (std::size_t i = 0; i < size; ++i) {\n",
    "        numbers[i] = static_cast<int>(i) * 10;\n",
    "    }\n",
    "\n",
    "    // 输出数组内容\n",
    "    std::cout << \"numbers 数组内容：\";\n",
    "    for (std::size_t i = 0; i < size; ++i) {\n",
    "        std::cout << numbers[i] << (i + 1 == size ? '\\n' : ' ');\n",
    "    }\n",
    "\n",
    "    // 无需 delete[]，unique_ptr 会自动调用正确的数组删除操作\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "示例三：结合自定义删除器管理资源（以文件句柄为例）\n",
    "- 自定义删除器可处理任意需要清理的资源（文件、互斥量等）。\n",
    "- 使用 `unique_ptr` 管理资源句柄，减少手动调用 `std::fclose` 的风险。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "成功写入文件：unique_ptr_demo.txt\n",
      "[FileCloser] 正在关闭文件。\n"
     ]
    }
   ],
   "source": [
    "#include <cstdio>   // 提供 std::FILE、std::fopen 等 C 标准库函数\n",
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <string>\n",
    "\n",
    "// 自定义删除器：当 unique_ptr 离开作用域时自动关闭文件\n",
    "struct FileCloser {\n",
    "    void operator()(std::FILE* fp) const noexcept {\n",
    "        if (fp) {\n",
    "            std::cout << \"[FileCloser] 正在关闭文件。\\n\";\n",
    "            std::fclose(fp);\n",
    "        }\n",
    "    }\n",
    "};\n",
    "\n",
    "{\n",
    "    // 打开文件并交由 unique_ptr 托管，指定 FileCloser 作为删除器\n",
    "    std::unique_ptr<std::FILE, FileCloser> file(std::fopen(\"unique_ptr_demo.txt\", \"w\"));\n",
    "    if (!file) {\n",
    "        std::cerr << \"无法打开文件，请检查权限或路径。\\n\";\n",
    "        return 1;\n",
    "    }\n",
    "\n",
    "    // 使用 get() 获取裸指针，执行写入操作\n",
    "    std::string text = \"使用 std::unique_ptr 管理文件资源。\\n\";\n",
    "    std::fputs(text.c_str(), file.get());\n",
    "    std::cout << \"成功写入文件：unique_ptr_demo.txt\\n\";\n",
    "\n",
    "    // 离开作用域时 FileCloser 自动生效，确保文件被关闭\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 使用捕获外部变量的 Lambda 作为 `std::unique_ptr` 的删除器来管理 `FILE*` 资源"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "已写入文件：demo.txt\n",
      "当前 log_count = 0（尚未关闭文件）\n",
      "[Lambda] 正在关闭文件。\n",
      "调用 file.reset() 后 log_count = 1（文件已关闭）\n"
     ]
    }
   ],
   "source": [
    "#include <cstdio>    // std::FILE, std::fopen, std::fclose, std::fputs\n",
    "#include <iostream>  // std::cout, std::cerr\n",
    "#include <memory>    // std::unique_ptr\n",
    "#include <string>    // std::string\n",
    "\n",
    "{\n",
    "    int log_count = 0; // 统计关闭文件的次数，用于验证 lambda 捕获是否生效\n",
    "\n",
    "    // 定义带捕获的 lambda 删除器：关闭文件并记录次数\n",
    "    auto closer = [&log_count](FILE* fp) {\n",
    "        if (fp) {\n",
    "            std::cout << \"[Lambda] 正在关闭文件。\\n\";\n",
    "            std::fclose(fp);\n",
    "            ++log_count;\n",
    "        }\n",
    "    };\n",
    "\n",
    "    // 使用 decltype(closer) 指定删除器类型，创建 unique_ptr 管理 FILE*\n",
    "    std::unique_ptr<FILE, decltype(closer)> file(std::fopen(\"demo.txt\", \"w\"), closer);\n",
    "    if (!file) {\n",
    "        std::cerr << \"打开文件失败，请检查路径或权限。\\n\";\n",
    "        return 1;\n",
    "    }\n",
    "\n",
    "    // 写入示例文本\n",
    "    const std::string text = \"使用 lambda 作为 unique_ptr 删除器的示例。\\n\";\n",
    "    std::fputs(text.c_str(), file.get());\n",
    "    std::cout << \"已写入文件：demo.txt\\n\";\n",
    "\n",
    "    // 此时文件仍然处于打开状态，删除器尚未触发\n",
    "    std::cout << \"当前 log_count = \" << log_count << \"（尚未关闭文件）\\n\";\n",
    "\n",
    "    // 主动释放所有权，触发 lambda 删除器\n",
    "    file.reset(); // 相当于手动调用删除器\n",
    "    std::cout << \"调用 file.reset() 后 log_count = \" << log_count << \"（文件已关闭）\\n\";\n",
    "\n",
    "    // 如果不调用 reset，在 main 结束时 unique_ptr 析构也会触发删除器\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# std::shared_ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`std::shared_ptr` 是 C++11 引入的共享所有权智能指针，在 C++17 中已成为管理动态资源的常用手段。它通过引用计数记录有多少个 `shared_ptr` 指向同一对象，当最后一个拥有者销毁或重置时，资源自动释放。核心特点如下：\n",
    "\n",
    "- **共享所有权**：多个 `shared_ptr` 实例可以同时指向同一资源，每次拷贝都会增加引用计数，析构或 `reset()` 会减少计数。\n",
    "- **异常安全**：配合 `std::make_shared` 构造对象，能在单次分配内创建控制块与对象，减少内存分配次数并提升异常安全性。\n",
    "- **与 `std::weak_ptr` 协作**：`weak_ptr` 作为弱引用不增加引用计数，可用来观察对象状态、打破循环引用。\n",
    "- **自定义删除器**：可指定对象释放方式，管理文件、套接字等非内存资源。\n",
    "- **消耗稍高**：相比 `std::unique_ptr`，`shared_ptr` 需要维护控制块和引用计数，存在额外内存与原子操作开销，适用于确实需要共享所有权的场景。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "示例一：基础共享所有权与引用计数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sp1 指向的值：2025\n",
      "use_count = 1（只有 sp1 持有）\n",
      "复制后 use_count = 2（sp1 与 sp2 共用）\n",
      "再次复制后 use_count = 3\n",
      "sp2 指向的值：2025\n",
      "sp3 指向的值：2025\n",
      "离开内部作用域后 use_count = 1\n",
      "调用 reset() 后 use_count = 0（为 0）\n",
      "sp1 是否为空？false\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <memory>\n",
    "\n",
    "{\n",
    "    // 使用 std::make_shared 创建共享对象，异常安全且一次分配\n",
    "    auto sp1 = std::make_shared<int>(2025);\n",
    "    std::cout << \"sp1 指向的值：\" << *sp1 << \"\\n\";\n",
    "    std::cout << \"use_count = \" << sp1.use_count() << \"（只有 sp1 持有）\\n\";\n",
    "\n",
    "    {\n",
    "        // 拷贝构造，引用计数 +1\n",
    "        auto sp2 = sp1;\n",
    "        std::cout << \"复制后 use_count = \" << sp1.use_count() << \"（sp1 与 sp2 共用）\\n\";\n",
    "\n",
    "        // 通过拷贝创建第三个共享指针\n",
    "        auto sp3 = sp2;\n",
    "        std::cout << \"再次复制后 use_count = \" << sp1.use_count() << \"\\n\";\n",
    "\n",
    "        std::cout << \"sp2 指向的值：\" << *sp2 << \"\\n\";\n",
    "        std::cout << \"sp3 指向的值：\" << *sp3 << \"\\n\";\n",
    "    } // 作用域结束，sp2 与 sp3 析构，引用计数各减 1\n",
    "\n",
    "    std::cout << \"离开内部作用域后 use_count = \" << sp1.use_count() << \"\\n\";\n",
    "\n",
    "    // reset 释放所有权，引用计数归零，资源被销毁\n",
    "    sp1.reset();\n",
    "    std::cout << \"调用 reset() 后 use_count = \" << sp1.use_count() << \"（为 0）\\n\";\n",
    "    std::cout << \"sp1 是否为空？\" << std::boolalpha << static_cast<bool>(sp1) << \"\\n\";\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "示例二：`std::shared_ptr` 与 `std::weak_ptr` 协同避免循环引用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[构造] Alice\n",
      "[构造] Bob\n",
      "Alice.use_count = 2\n",
      "Bob.use_count   = 2\n",
      "[构造] Carol\n",
      "[构造] Dave\n",
      "Carol 的母亲是 Alice\n",
      "Carol 的父亲是 Bob\n",
      "[析构] Dave\n",
      "[析构] Carol\n",
      "[析构] Bob\n",
      "[析构] Alice\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <string>\n",
    "\n",
    "struct Person {\n",
    "    std::string name;\n",
    "    std::shared_ptr<Person> partner; // 如果双向都用 shared_ptr 会引发循环引用\n",
    "    std::weak_ptr<Person> mother;    // weak_ptr 不增加引用计数\n",
    "    std::weak_ptr<Person> father;\n",
    "\n",
    "    explicit Person(std::string n) : name(std::move(n)) {\n",
    "        std::cout << \"[构造] \" << name << \"\\n\";\n",
    "    }\n",
    "    ~Person() {\n",
    "        std::cout << \"[析构] \" << name << \"\\n\";\n",
    "    }\n",
    "};\n",
    "\n",
    "{\n",
    "    std::shared_ptr<Person> alice = std::make_shared<Person>(\"Alice\");\n",
    "    std::shared_ptr<Person> bob   = std::make_shared<Person>(\"Bob\");\n",
    "\n",
    "    // 错误示例：若双方都使用 shared_ptr，会形成引用环，导致无法释放\n",
    "    alice->partner = bob;\n",
    "    bob->partner   = alice;\n",
    "\n",
    "    std::cout << \"Alice.use_count = \" << alice.use_count() << \"\\n\";\n",
    "    std::cout << \"Bob.use_count   = \" << bob.use_count() << \"\\n\";\n",
    "\n",
    "    // 创建父母并用 weak_ptr 连接孩子，打破潜在环\n",
    "    auto carol = std::make_shared<Person>(\"Carol\");\n",
    "    auto dave  = std::make_shared<Person>(\"Dave\");\n",
    "\n",
    "    carol->mother = alice;\n",
    "    carol->father = bob;\n",
    "    alice->partner.reset(); // 解除强引用\n",
    "    bob->partner.reset();   // 解除强引用\n",
    "\n",
    "    if (auto mom = carol->mother.lock()) {\n",
    "        std::cout << \"Carol 的母亲是 \" << mom->name << \"\\n\";\n",
    "    }\n",
    "    if (auto dad = carol->father.lock()) {\n",
    "        std::cout << \"Carol 的父亲是 \" << dad->name << \"\\n\";\n",
    "    }\n",
    "\n",
    "    // 离开作用域时，Alice、Bob、Carol、Dave 均能正确析构\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[构造] Alice\n",
      "[构造] Bob\n",
      "[构造] Carol\n",
      "Carol 当前 use_count = 3\n",
      "Carol 的母亲是 Alice\n",
      "Carol 的父亲是 Bob\n",
      "Alice children 数量：1\n",
      "Bob   children 数量：1\n",
      "[析构] Carol\n",
      "清空 children 后，Alice children 数量：0\n",
      "清空 children 后，Bob   children 数量：0\n",
      "[析构] Bob\n",
      "[析构] Alice\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <string>\n",
    "#include <vector>\n",
    "\n",
    "struct Person {\n",
    "    std::string name;\n",
    "    // 孩子对父母只需要“观察”关系，不拥有 -> weak_ptr\n",
    "    std::weak_ptr<Person> mother;\n",
    "    std::weak_ptr<Person> father;\n",
    "    // 父母拥有孩子 -> shared_ptr\n",
    "    std::vector<std::shared_ptr<Person>> children;\n",
    "\n",
    "    explicit Person(std::string n) : name(std::move(n)) {\n",
    "        std::cout << \"[构造] \" << name << \"\\n\";\n",
    "    }\n",
    "    ~Person() {\n",
    "        std::cout << \"[析构] \" << name << \"\\n\";\n",
    "    }\n",
    "};\n",
    "\n",
    "{\n",
    "    std::shared_ptr<Person> alice = std::make_shared<Person>(\"Alice\");\n",
    "    std::shared_ptr<Person> bob   = std::make_shared<Person>(\"Bob\");\n",
    "\n",
    "    {\n",
    "        auto carol = std::make_shared<Person>(\"Carol\");\n",
    "\n",
    "        // 父母拥有孩子：shared_ptr 增加引用计数\n",
    "        alice->children.push_back(carol);\n",
    "        bob->children.push_back(carol);\n",
    "\n",
    "        // 孩子引用父母：weak_ptr 不增加引用计数\n",
    "        carol->mother = alice;\n",
    "        carol->father = bob;\n",
    "\n",
    "        std::cout << \"Carol 当前 use_count = \" << carol.use_count() << \"\\n\";\n",
    "\n",
    "        // 使用 lock() 安全访问父母\n",
    "        if (auto mom = carol->mother.lock()) {\n",
    "            std::cout << \"Carol 的母亲是 \" << mom->name << \"\\n\";\n",
    "        }\n",
    "        if (auto dad = carol->father.lock()) {\n",
    "            std::cout << \"Carol 的父亲是 \" << dad->name << \"\\n\";\n",
    "        }\n",
    "    } // carol 的最外层 shared_ptr 离开作用域，引用计数减 1\n",
    "\n",
    "    // 此时 carol 仍被父母的 children 持有，因此尚未析构\n",
    "    std::cout << \"Alice children 数量：\" << alice->children.size() << \"\\n\";\n",
    "    std::cout << \"Bob   children 数量：\" << bob->children.size() << \"\\n\";\n",
    "\n",
    "    // 手动清空孩子列表，carol 引用计数归零 -> 自动析构\n",
    "    alice->children.clear();\n",
    "    bob->children.clear();\n",
    "\n",
    "    std::cout << \"清空 children 后，Alice children 数量：\" << alice->children.size() << \"\\n\";\n",
    "    std::cout << \"清空 children 后，Bob   children 数量：\" << bob->children.size() << \"\\n\";\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "示例三：自定义删除器管理非内存资源"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "文件 use_count = 2\n",
      "写入完成，等待作用域结束自动关闭。\n",
      "最终 file.use_count = 1\n",
      "[自定义删除器] 自动关闭文件。\n"
     ]
    }
   ],
   "source": [
    "#include <cstdio>\n",
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <string>\n",
    "\n",
    "{\n",
    "    // 自定义删除器：关闭文件并打印日志\n",
    "    auto file_deleter = [](std::FILE* fp) {\n",
    "        if (fp) {\n",
    "            std::cout << \"[自定义删除器] 自动关闭文件。\\n\";\n",
    "            std::fclose(fp);\n",
    "        }\n",
    "    };\n",
    "\n",
    "    // shared_ptr 支持自定义删除器，适合需要共享文件句柄的场景\n",
    "    std::shared_ptr<std::FILE> file(std::fopen(\"shared_ptr_demo.txt\", \"w\"), file_deleter);\n",
    "    if (!file) {\n",
    "        std::cerr << \"打开文件失败。\\n\";\n",
    "        return 1;\n",
    "    }\n",
    "\n",
    "    {\n",
    "        // 多个 shared_ptr 共享同一个文件句柄\n",
    "        auto file_copy = file;\n",
    "        std::cout << \"文件 use_count = \" << file.use_count() << \"\\n\";\n",
    "\n",
    "        const std::string text = \"使用 std::shared_ptr 管理 FILE*，配合自定义删除器。\\n\";\n",
    "        std::fputs(text.c_str(), file.get());\n",
    "        std::cout << \"写入完成，等待作用域结束自动关闭。\\n\";\n",
    "    } // file_copy 析构，引用计数减 1，但文件仍由 file 持有\n",
    "\n",
    "    std::cout << \"最终 file.use_count = \" << file.use_count() << \"\\n\";\n",
    "\n",
    "    // 最后一个 shared_ptr 离开作用域时，删除器被调用，文件自动关闭\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## enable_shared_from_this"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在一个对象已经由 `std::shared_ptr` 管理的情况下，直接构造新的 `std::shared_ptr(this)` 会导致**双重管理**（两份引用计数），最终引发重复析构。当 `enable_shared_from_this` 正确使用时，它可以保证：\n",
    "\n",
    "- 生成的 `shared_ptr` 与现有的引用计数共享控制块；\n",
    "- 避免多次析构或内存泄漏；\n",
    "- 允许对象内部安全地获取 `shared_ptr`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// https://godbolt.org/z/K5P69Pq4j double free or corruption (out)\n",
    "\n",
    "#include <iostream>\n",
    "#include <memory>\n",
    "\n",
    "class Foo {\n",
    "public:\n",
    "    Foo() { std::cout << \"Foo constructed\\n\"; }\n",
    "    ~Foo() { std::cout << \"Foo destructed\\n\"; }\n",
    "\n",
    "    void do_something() {\n",
    "        // ⚠️ 错误示范：构造新的 shared_ptr(this)\n",
    "        std::shared_ptr<Foo> self(this);\n",
    "        std::cout << \"Inside do_something, use_count = \"\n",
    "                  << self.use_count() << \"\\n\";\n",
    "    }\n",
    "};\n",
    "\n",
    "int main() {\n",
    "    {\n",
    "        // 外部使用 shared_ptr 管理对象\n",
    "        std::shared_ptr<Foo> sp = std::make_shared<Foo>();\n",
    "        sp->do_something();  // 内部又构造了一个 shared_ptr(this)\n",
    "    } // 离开作用域后，外部 shared_ptr 析构，控制块计数归零 -> 析构 Foo\n",
    "\n",
    "    std::cout << \"Program ends\\n\";\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// https://godbolt.org/z/GjWW4jEvr\n",
    "\n",
    "#include <iostream>\n",
    "#include <memory>\n",
    "\n",
    "class Foo : public std::enable_shared_from_this<Foo> {\n",
    "public:\n",
    "    void do_something() {\n",
    "        // 在成员函数内部获取 shared_ptr<Foo>\n",
    "        std::shared_ptr<Foo> self = shared_from_this();\n",
    "        std::cout << \"use_count = \" << self.use_count() << \"\\n\";\n",
    "    }\n",
    "};\n",
    "\n",
    "{\n",
    "    // auto sp = std::make_shared<Foo>();\n",
    "    // sp->do_something();  // 打印 use_count = 1（或更多，视上下文而定）\n",
    "\n",
    "    // 如果尝试 Foo foo; foo.do_something(); 将抛出 std::bad_weak_ptr\n",
    "    Foo foo; \n",
    "    foo.do_something();\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "use_count = 2\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <memory>\n",
    "\n",
    "class Foo : public std::enable_shared_from_this<Foo> {\n",
    "public:\n",
    "    void do_something() {\n",
    "        // 在成员函数内部获取 shared_ptr<Foo>\n",
    "        std::shared_ptr<Foo> self = shared_from_this();\n",
    "        std::cout << \"use_count = \" << self.use_count() << \"\\n\";\n",
    "    }\n",
    "};\n",
    "\n",
    "{\n",
    "    auto sp = std::make_shared<Foo>();\n",
    "    sp->do_something();  // 打印 use_count = 1（或更多，视上下文而定）\n",
    "\n",
    "    // 如果尝试 Foo foo; foo.do_something(); 将抛出 std::bad_weak_ptr\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**要点：**\n",
    "\n",
    "1. 只有当对象**真的被 `shared_ptr` 管理**时，`shared_from_this()` 才有效；否则会抛出 `std::bad_weak_ptr` 异常。\n",
    "2. 通常用 `std::make_shared` 来创建对象，确保控制块和对象内存布局符合 enable_shared_from_this 的预期。\n",
    "3. `enable_shared_from_this` 内部维护了一个 `std::weak_ptr<T>`，保存了对自身的弱引用；`shared_from_this()` 会对其 lock，从而生成与外部 `shared_ptr` 共用控制块的新 `shared_ptr`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "常见使用场景\n",
    "\n",
    "- **事件回调/异步操作**：在异步操作回调中保持对象存活。例如启动一个异步任务时，把 `shared_from_this()` 传入回调，确保回调执行时对象未被销毁。\n",
    "- **容器自注册**：对象需要把自身交给某个全局管理容器，容器要求持有 `shared_ptr`。\n",
    "- **链式结构**：构建复杂图结构或树结构时，有时需要节点互相持有 `shared_ptr`。虽然应注意避免循环引用，但 `enable_shared_from_this` 能提供正确的 `shared_ptr` 获取方式。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用注意事项"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **避免 `this` 直接构造 shared_ptr**\n",
    "\n",
    "```cpp\n",
    "std::shared_ptr<Foo> bad(this);     // 错误，产生第二个控制块\n",
    "std::shared_ptr<Foo> good = shared_from_this(); // 正确\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **必须由 shared_ptr 管理**\n",
    "\n",
    "对象必须先交给 `std::shared_ptr` 托管，否则 `shared_from_this()` 抛出异常。这也意味着不能在栈上直接调用：\n",
    "```cpp\n",
    "Foo foo;\n",
    "foo.do_something(); // 触发 std::bad_weak_ptr\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **构造过程中不要提前 shared_from_this()**\n",
    "\n",
    "在对象构造函数尚未完全执行、`shared_ptr` 还没接管之前调用 `shared_from_this()` 是未定义行为。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **继承结构**\n",
    "\n",
    "如果多重继承或模板继承，确保 `enable_shared_from_this<Base>` 与实际使用的 `shared_ptr<Base>` 匹配，避免 `slicings` 或类型不一致。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 循环引用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 先理解 `std::shared_ptr` 的引用计数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`std::shared_ptr` 背后有一个**控制块**，其中存着两个数字：\n",
    "- `use_count`（强引用计数）：当前有多少个 `shared_ptr` 拥有这份资源。\n",
    "- `weak_count`（弱引用计数）：当前有多少个 `weak_ptr` 在观察这份资源。\n",
    "只有当 `use_count` 变成 0 时，对象才会被销毁。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 循环引用产生的本质"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "两位朋友 Alice 与 Bob，互相把对方列成“我的好友”。代码上就是 Alice 持有 Bob 的 `shared_ptr`，Bob 同样持有 Alice 的 `shared_ptr`。\n",
    "\n",
    "用图表示：\n",
    "\n",
    "![circular_reference](./circular_reference.png)\n",
    "\n",
    "- Alice 的控制块 `use_count` ≥ 1（至少被 Bob 的 `shared_ptr` 持有）。\n",
    "- Bob 的控制块 `use_count` ≥ 1（至少被 Alice 的 `shared_ptr` 持有）。\n",
    "\n",
    "当外层函数结束时，原本的 `shared_ptr<Alice>` 和 `shared_ptr<Bob>` 都离开了作用域，但由于彼此内部还各自持有对方，此时两个对象的 `use_count` 依旧是 1，没有人能变成 0，所以他们永远不会被销毁——形成内存泄漏。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `std::weak_ptr` 做什么？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `std::weak_ptr` 只记录指向对象的地址，**不参与引用计数**；它不会让 `use_count` 增加。\n",
    "- 当需要真正使用对象时，通过 `weak_ptr.lock()` 获取一个临时的 `shared_ptr`：\n",
    "  - 如果对象还活着，返回有效的 `shared_ptr`。\n",
    "  - 如果对象已经销毁，返回 `nullptr`，避免非法访问。\n",
    "\n",
    "换句话说，`weak_ptr` 就像是“心里记着这个朋友”，但不再“正式占位拥有”。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 完整示例对比：有循环 vs. 打破循环"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 循环引用导致析构无法触发"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[构造] Alice\n",
      "[构造] Bob\n",
      "Alice.use_count = 2\n",
      "Bob.use_count   = 2\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <string>\n",
    "\n",
    "struct Person {\n",
    "    std::string name;\n",
    "    std::shared_ptr<Person> partner; // 互相持有 shared_ptr -> 循环引用\n",
    "    Person(std::string n) : name(std::move(n)) {\n",
    "        std::cout << \"[构造] \" << name << \"\\n\";\n",
    "    }\n",
    "    ~Person() {\n",
    "        std::cout << \"[析构] \" << name << \"\\n\";\n",
    "    }\n",
    "};\n",
    "\n",
    "{\n",
    "    auto alice = std::make_shared<Person>(\"Alice\");\n",
    "    auto bob   = std::make_shared<Person>(\"Bob\");\n",
    "\n",
    "    alice->partner = bob;\n",
    "    bob->partner   = alice;\n",
    "\n",
    "    std::cout << \"Alice.use_count = \" << alice.use_count() << \"\\n\";\n",
    "    std::cout << \"Bob.use_count   = \" << bob.use_count() << \"\\n\";\n",
    "\n",
    "    // 程序结束，原本应该析构，却不会出现析构输出\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 使用 `weak_ptr` 打破循环"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[构造] Alice\n",
      "[构造] Bob\n",
      "Alice.use_count = 1\n",
      "Bob.use_count   = 1\n",
      "Alice.use_count = 1\n",
      "Bob.use_count   = 1\n",
      "Alice 的伴侣是 Bob\n",
      "Bob 的伴侣是 Alice\n",
      "[析构] Bob\n",
      "[析构] Alice\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <string>\n",
    "\n",
    "struct Person {\n",
    "    std::string name;\n",
    "    std::weak_ptr<Person> partner; // 通过 weak_ptr 避免循环引用\n",
    "\n",
    "    explicit Person(std::string n) : name(std::move(n)) {\n",
    "        std::cout << \"[构造] \" << name << \"\\n\";\n",
    "    }\n",
    "    ~Person() {\n",
    "        std::cout << \"[析构] \" << name << \"\\n\";\n",
    "    }\n",
    "\n",
    "    void show_partner() const {\n",
    "        if (auto sp = partner.lock()) {\n",
    "            std::cout << name << \" 的伴侣是 \" << sp->name << \"\\n\";\n",
    "        } else {\n",
    "            std::cout << name << \" 暂无伴侣\\n\";\n",
    "        }\n",
    "    }\n",
    "};\n",
    "\n",
    "{\n",
    "    {\n",
    "        // 各自拥有各自的对象，引用计数初始为 1\n",
    "        auto alice = std::make_shared<Person>(\"Alice\");\n",
    "        auto bob   = std::make_shared<Person>(\"Bob\");\n",
    "\n",
    "        alice->partner = bob; // weak_ptr，不增加 use_count\n",
    "        std::cout << \"Alice.use_count = \" << alice.use_count() << \"\\n\";\n",
    "        std::cout << \"Bob.use_count   = \" << bob.use_count() << \"\\n\";\n",
    "\n",
    "        bob->partner = alice; // weak_ptr，同样不增加\n",
    "        std::cout << \"Alice.use_count = \" << alice.use_count() << \"\\n\";\n",
    "        std::cout << \"Bob.use_count   = \" << bob.use_count() << \"\\n\";\n",
    "\n",
    "        alice->show_partner();\n",
    "        bob->show_partner();\n",
    "    } // 作用域结束，引用计数归零，析构函数被调用\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 理解流程：引用计数的变化表"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 时刻                       | Alice.use_count | Bob.use_count | 说明                                 |\n",
    "| -------------------------- | --------------- | ------------- | ------------------------------------ |\n",
    "| 创建 `alice`               | 1               | —             | `alice` 拥有 Alice                   |\n",
    "| 创建 `bob`                 | 1               | 1             | `bob` 拥有 Bob                       |\n",
    "| Alice.partner = Bob (weak) | 1               | 1             | `weak_ptr` 不改变引用计数            |\n",
    "| Bob.partner = Alice (weak) | 1               | 1             | 同上                                 |\n",
    "| main 结束（alice/bob析构） | 0               | 0             | 最后一个 `shared_ptr` 离开，触发析构 |\n",
    "\n",
    "如果把 `weak_ptr` 改回 `shared_ptr`，那条 “ = 1 ” 会变成 “ = 2 ”，最后也就不会降到 0。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结要点"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. **循环引用产生的原因**：强引用（`shared_ptr`）互相持有，导致 `use_count` 永远不归零。\n",
    "2. **`weak_ptr` 的角色**：弱引用，不占据拥有权，避免引用计数被卡住。\n",
    "3. **使用时机**：当 A 需要指向 B，但 A 不是 B 的“生杀大权”拥有者时，使用 `weak_ptr`；需要访问时，用 `lock()` 短暂借一个 `shared_ptr`。\n",
    "\n",
    "建议你实际运行上面的两段程序，对比输出情况，直观感受引用计数的差异。这样你就能真正理解为什么必须用 `weak_ptr` 来打破循环引用了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Benchmark"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "! cd bench && g++ -std=c++20 -O2 benchmark_test.cpp -lbenchmark -lpthread -o benchmark_test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "! cd bench && ./benchmark_test --benchmark_repetitions=5 --benchmark_report_aggregates_only=true"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "TL;DR\n",
    "- **shared_ptr 拷贝（Copy）**：单线程 ~0.9 ns/次，但 2 线程以上吞吐量急剧下降，16 线程时几乎退化到 ~54M ops/s（每次 ~18.4 ns）。说明引用计数的原子操作在多线程下高度争用。\n",
    "- **shared_ptr reset**：单线程 18.9 ns/次，但 16 线程总吞吐量反而上升为 2.45M ns/次（实测 2.46 ms/100万个，即 2.46 ns/次 *每线程*），不过 wall-clock 明显展示出竞争（CPU 时间大幅上升），仍需谨慎。\n",
    "- **unique_ptr 系列**：仍稳定在单线程下；没有多线程版本，因为本质上不会共享所有权，也避免了原子操作争用。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "codemirror_mode": "text/x-c++src",
   "file_extension": ".cpp",
   "mimetype": "text/x-c++src",
   "name": "c++",
   "version": "17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
